package betower

import (
	"go.uber.org/zap"
	"sync"
	"time"
	"wzgames/internal/constant"
	"wzgames/internal/gloader"
	"wzgames/internal/gloader/election"
	"wzgames/pkg/actor/actor"
	"wzgames/pkg/actor/actorservice"
	"wzgames/pkg/common/timingwheel"
	"wzgames/pkg/logger"
)

var (
	btGuard *BetTowerGuard
	once    sync.Once
)

type BetTowerGuard struct {
	actorservice.ServiceMeta
	timerWheel *timingwheel.TimingWheel
	stmVerMgr  *StmVerMgr

	elect *election.Election
}

type StartElection struct{}

func Actor() actorservice.IService {
	if btGuard == nil {
		once.Do(func() {
			btGuard = &BetTowerGuard{
				timerWheel: timingwheel.NewTimingWheel(time.Millisecond, 100),
				stmVerMgr:  &StmVerMgr{},
			}
			btGuard.Name = "actor_bet_tower_guard"
			btGuard.elect = election.NewElection(constant.CcBetTowerElectPath, gloader.BootConfig().GetNodeID(), btGuard.electionCallback)
			btGuard.stmVerMgr.Init()
		})
	}
	return btGuard
}

func (bt *BetTowerGuard) OnReceive(ctx actor.Context) {
	switch ctx.Message().(type) {
	case StartElection:
		bt.doElection()
	default:
	}
}

func (bt *BetTowerGuard) OnStart(as *actorservice.ActorService) {
	bt.timerWheel.Start()
}

func (bt *BetTowerGuard) Attach(a interface{}) {
}

// doElection 选举master，进行流水版本管理
func (bt *BetTowerGuard) doElection() {
	err := bt.elect.Start(gloader.CClient())
	if err != nil {
		logger.Error("[BetTower] do election fail", zap.Error(err))
	}
}

func TimerAfter(d time.Duration, fn func(interface{}), args interface{}) *timingwheel.Timer {
	return btGuard.timerWheel.AfterFunc(d, fn, args)
}

func (bt *BetTowerGuard) electionCallback(evt election.MasterEvent) {
	// 作为master，启动流水版本管理
	bt.stmVerMgr.Start()
	logger.Info("[BetTower] bet tower master start", zap.String("NodeID", gloader.BootConfig().GetNodeID()))
}

func (bt *BetTowerGuard) OnDestroy() {
	bt.timerWheel.Stop()
	bt.elect.Stop()
	StmMgr().Destroy()
	bt.stmVerMgr.Stop()
	actorservice.Stop(bt.GetPID())
}
